/** \file    lab_color.h
  * \brief   Everything concerning LAB and sLAB color systems.
  * \date    2001
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/lab_color.h,v 1.1 2004/02/04 14:43:24 cscom1r4 Exp $
  */

#ifndef _lab_color_h_
#define _lab_color_h_

#include "imglib/imageclass_decl.h"

namespace img {

template< class T > 
double lab_l(const T &rgb);

template< class T > 
double lab_a(const T &rgb);

template< class T > 
double lab_b(const T &rgb);

///replaces r,g,b components of any class on l,a,b components
template< class T > 
T rgb2lab( const T & rhs );

template< class in, class out >
void rgb2lab( const in & rgb, out & lab );

///extracts two components of the (complex) chromaticity from a color
template <class C>
inline complex_color lab_chromaticity(const C &c);

///extracts lightness component from a color
template <class C>
inline double lab_lightness(const C &c);

class strength_luminosity: public std::unary_function <const byte_color &, float_color> {
public:
	strength_luminosity( double factor ) : _factor(factor) {}
	float_color operator() ( const byte_color & rhs ) const {
		float_color lab;
		rgb2lab( rhs, lab );
		lab.r *= _factor;
		float_color rgb;
		rgb2lab( lab, rgb );
		return rgb;
	}
private:
	double _factor;
};


//////////////////////////
// template definitions //
//////////////////////////

const double _rsq2 = 1.0 / sqrt(2.0);
const double _rsq3 = 1.0 / sqrt(3.0);
const double _rsq6 = 1.0 / sqrt(6.0);
const double _sq6r3 = sqrt(6.0) / 3.0;

template< class T > 
inline double lab_l(const T &rgb)
	{ return _rsq3 * (rgb.r + rgb.g + rgb.b ); }

template< class T > 
inline double lab_a(const T &rgb)
	{ return _rsq2 * (rgb.r - rgb.g ); }

template< class T > 
inline double lab_b(const T &rgb)
	{ return _rsq6 * ( - rgb.r - rgb.g ) + _sq6r3 * rgb.b; }

template< class T >
inline T rgb2lab( const T & rhs ) 
	{ return T(lab_l(rhs), lab_a(rhs), lab_b(rhs)); }

template< class in, class out >
inline void rgb2lab( const in & rgb, out & lab ) {
	lab.r = lab_l(rgb);
	lab.g = lab_a(rgb);
	lab.b = lab_b(rgb);
}

template <class C>
inline complex_color lab_chromaticity(const C &rgb)
	{ return complex_color(lab_a(rgb), lab_b(rgb)); }

template <class C>
inline double lab_lightness(const C &rgb)
	{ return lab_l(rgb); }

} //namespace img

#endif //_lab_color_h_
